﻿using System;
using System.Collections.Generic;
using System.Text;
using SampleFramework;
using SlimDX;
using SlimDX.Direct3D9;

namespace Nimue.Spatial
{
    class OctreeNode
    {
        #region Fields
        private Vector3 center;
        private float width, height, depth;
        private float radius;

        private OctreeNode[,,] childNodes;
        private LinkedList<Object> entities;
        #endregion

        #region Public Properties
        public Vector3 Center
        {
            get { return center; }
        }

        public float Width
        {
            get { return width; }
        }
        public float Height
        {
            get { return height; }
        }
        public float Depth
        {
            get { return depth; }
        }

        public float Radius
        {
            get { return radius; }
        }

        public OctreeNode[,,] ChildNodes
        {
            get { return childNodes; }
        }

        public LinkedList<Object> Entities
        {
            get { return entities; }
        }
        #endregion

        #region Constructor
        public OctreeNode(Vector3 center, float width, float height, float depth, LinkedList<Object> entities)
        {
            this.center = center;
            this.width = width;
            this.height = height;
            this.depth = depth;
            this.entities = entities;
            this.radius = (float)Math.Sqrt(width * width + height * height + depth * depth) * 0.5f;
        }
        #endregion

        #region Subdivision
        public void Subdivide(int maximumNumberOfEntities, int maximumNumberOfLevels, int currentNumberOfLevels)
        {
            if (currentNumberOfLevels == maximumNumberOfLevels)
                return;
            if (entities != null && entities.Count <= maximumNumberOfEntities)
                return;

            childNodes = new OctreeNode[2, 2, 2];
            Vector3 nodeCenter = Vector3.Zero;
            float newWidth = width * 0.5f, newHeight = height * 0.5f, newDepth = depth * 0.5f;
            LinkedList<Object> newEntities = new LinkedList<object>();

            for (int z = 0; z < 2; z++)
                for (int y = 0; y < 2; y++)
                    for (int x = 0; x < 2; x++)
                    {
                        nodeCenter = center + new Vector3(
                            ((x < 1) ? -newWidth : newWidth) * 0.5f,
                            ((y < 1) ? -newHeight : newHeight) * 0.5f,
                            ((z < 1) ? -newDepth : newDepth) * 0.5f);
                        newEntities = OctreeNode.Intersects(nodeCenter, newWidth, newHeight, newDepth, entities);
                        childNodes[x, y, z] = new OctreeNode(nodeCenter, newWidth, newHeight, newDepth, newEntities);
                        if (newEntities.Count > maximumNumberOfEntities)
                            childNodes[x, y, z].Subdivide(maximumNumberOfEntities, maximumNumberOfLevels, currentNumberOfLevels++);
                    }

            entities.Clear();
        }
        #endregion

        #region Intersection

        public static LinkedList<object> Intersects(Vector3 center, float width, float height, float depth, LinkedList<object> entities)
        {
            LinkedList<object> newList = new LinkedList<object>();

            foreach (object entity in entities)
                if (OctreeNode.Intersects(center, width, height, depth, entity))
                    newList.AddLast(entity);

            return newList;
        }

        public static bool Intersects(Vector3 center, float width, float height, float depth, object entity)
        {
            //TODO
            return true;
        }
        #endregion
    }
}
